package com.sky.directdeal.utils;

import android.content.Context;
import android.location.Criteria;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;

import com.sky.directdeal.model.LocationAddress;


public class LocationProvider {

	private static final int TWO_MINUTES = 1000 * 60 * 2;

	private static LocationProvider sInstance;
	private LocationManager locationManager;
	private volatile boolean isLocationRegistered=false;
	private LocationAddress locationAddress;

	public static synchronized LocationProvider getInstance() {

		if (sInstance == null) {
			sInstance = new LocationProvider();
		}

		return sInstance;
	}

	private final LocationListener locationListener = new LocationListener() {

		@Override
		public void onLocationChanged(Location location) {

			if (locationManager != null) {
				locationManager.removeUpdates(this);
				locationManager = null;
			}

			isLocationRegistered = false;
		}

		@Override
		public void onProviderDisabled(String provider) {
		}

		@Override
		public void onProviderEnabled(String provider) {
		}

		@Override
		public void onStatusChanged(String provider, int status, Bundle extras) {
		}
	};

	public synchronized Location getLocationEx(Context context) {
		Location loc = null;

		if(null == locationManager){
			locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
		}

		if (null == locationManager) {
			return null;
		}

		final String provider = locationManager.getBestProvider(new Criteria(), true);

		if (null != provider && !isLocationRegistered) {

			try {

				locationManager.requestLocationUpdates(provider, 0, 0, locationListener);
				isLocationRegistered = true;

			} catch (Exception e) {
			}
		}
		try {
			loc = fetchLocationEx();
		} catch (Exception e) {
		}
		return loc;
	}

	private Location fetchLocationEx() {

		Location bestProviderLoc = null, gpsLoc = null, curLoc = null;
		boolean gpsEnabled = false;
		boolean networkEnabled = false;

		try{gpsEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);}catch(Exception ex){}
		if(gpsEnabled){
			gpsLoc = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
		}
		if(gpsLoc == null){
			try{networkEnabled = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);}catch(Exception ex){}
			if(networkEnabled){
				gpsLoc = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
			}
		}

		if(gpsLoc==null){

			final String bestProvider = locationManager.getBestProvider(new Criteria(), true);


			if (null != bestProvider) {
				bestProviderLoc = locationManager.getLastKnownLocation(bestProvider);
			}

		}

		// if there are both values use the latest one
		if (gpsLoc != null && bestProviderLoc != null) {
			curLoc = getBetterLocation(gpsLoc, bestProviderLoc);
		} else if (gpsLoc != null) {
			curLoc = gpsLoc;
		} else if (bestProviderLoc != null) {
			curLoc = bestProviderLoc;
		}

		return curLoc;
	}

	
	protected Location getBetterLocation(Location newLocation, Location currentBestLocation) {

		if (currentBestLocation == null) {
			// A new location is always better than no location
			return newLocation;
		}

		// Check whether the new location fix is newer or older
		long timeDelta = newLocation.getTime() - currentBestLocation.getTime();
		boolean isSignificantlyNewer = timeDelta > TWO_MINUTES;
		boolean isSignificantlyOlder = timeDelta < -TWO_MINUTES;
		boolean isNewer = timeDelta > 0;

		// If it's been more than two minutes since the current location, use the new location
		// because the user has likely moved.
		if (isSignificantlyNewer) {
			return newLocation;
			// If the new location is more than two minutes older, it must be worse
		} else if (isSignificantlyOlder) {
			return currentBestLocation;
		}

		// Check whether the new location fix is more or less accurate
		int accuracyDelta = (int) (newLocation.getAccuracy() - currentBestLocation.getAccuracy());
		boolean isLessAccurate = accuracyDelta > 0;
		boolean isMoreAccurate = accuracyDelta < 0;
		boolean isSignificantlyLessAccurate = accuracyDelta > 200;

		// Check if the old and new location are from the same provider
		boolean isFromSameProvider = isSameProvider(newLocation.getProvider(),
				currentBestLocation.getProvider());

		// Determine location quality using a combination of timeliness and accuracy
		if (isMoreAccurate) {
			return newLocation;
		} else if (isNewer && !isLessAccurate) {
			return newLocation;
		} else if (isNewer && !isSignificantlyLessAccurate && isFromSameProvider) {
			return newLocation;
		}
		return currentBestLocation;
	}

	/** Checks whether two providers are the same */
	private boolean isSameProvider(String provider1, String provider2) {
		if (provider1 == null) {
			return provider2 == null;
		}
		return provider1.equals(provider2);
	}

	public void unRegisterListener() {
		if (locationManager != null) {
			locationManager.removeUpdates(locationListener);
			isLocationRegistered = false;
			locationManager=null;
		}
	}

	public LocationAddress getLocationAddress() {
		return locationAddress;
	}

	public void setLocationAddress(LocationAddress locationAddress) {
		this.locationAddress = locationAddress;
	}
	
	
}